﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Red.Controls;
using Red.Controls.Shell;
using Red.Controls.ViewModels;
using Red.Core.Extensions;
using Red.Launcher.Utilities;
using Database = Red.Launcher.ViewModels.Workspaces.Database;
using Dialog = Red.Launcher.Utilities.Dialog;
using Tree = Red.Launcher.ViewModels.Workspaces.Admin.Tree;

namespace Red.Launcher.Menus.Workspaces.Admin
{
    public partial class UserListDialog : RedWindow, Dialog.IEvents
    {
        #region Private Data

        private bool _okEnabled = true;
        private readonly Tree.Root _root;
        private Database.Record _users;

        private CommandPalette _picker = new CommandPalette();
        private Dictionary<Type, RecordDetailView> _recordViewControls;

        #endregion Private Data

        #region C-Tor

        partial void InitializeAnalytics();

        public UserListDialog()
        {
            InitializeComponent();

            DataContext = this;

            _root = new Tree.Root();

            Database.Record data = new Database.SuperGroup();

            Tree.Item item = new Tree.Item( _root, data, null, false );
            _root.Items.Add( item );

            _users = new Database.VirtualUserGroup()
            {
                Name = "All Users"
            };

            data.AddChild( ref _users );

            item.BuildOnChildCollectionChanged = true;

            _root.RebuildAsync().DoNotAwait();

            _root.Filter = new Predicate<object>( Filter );
            _filter.TextChanged += _filter_TextChanged;

            _tree.DataContext = _root;

            _recordViewControls = new Dictionary<Type, RecordDetailView>()
            {
                { typeof( Database.SuperGroup ), _superGroupDetailView },
                { typeof( Database.VirtualUserGroup ), _userGroupDetailView },
                { typeof( Database.AssignedUserGroup ), _assignedUserGroupDetailView },
                { typeof( Database.User ), _userDetailView },
                { typeof( Database.AssignedUser ), _assignedUserDetailView },
                { typeof( Database.P4Credential ), _credentialsDetailView },
                { typeof( Database.P4ClientWorkspace ), _workspaceDetailView },
                { typeof( Database.ClientParameter ), _parameterDetailView },
            };

            foreach ( KeyValuePair<Type, RecordDetailView> pair in _recordViewControls )
            {
                pair.Value.Visibility = Visibility.Hidden;

                //This merely stops wpf from spewing binding errors into the console whilst the datacontext is still inherited from the dialog
                pair.Value.DataContext = null;
            }

            _import.Click += _import_Click;

            InitializeAnalytics();
        }

        #endregion C-Tor

        #region Private Methods

        private void SetDialogLocation( Window dialog )
        {
            Point mousePos = PointToScreen( Mouse.GetPosition( this ) );
            dialog.Top = mousePos.Y;
            dialog.Left = mousePos.X;
        }

        private void ShowPicker<TOrignalType, TAssignType>( Database.Record parent )
            where TOrignalType : Database.Record
            where TAssignType : Database.Record
        {
            List<CommandPaletteItem> items = new List<CommandPaletteItem>();

            foreach ( Database.Record child in parent.Children )
            {
                CommandPaletteItem<Database.Record> childRecord = new CommandPaletteItem<Database.Record>( child )
                {
                    Name = child.Name
                };

                Tree.Item item = (Tree.Item)_tree.SelectedItem;

                childRecord.Click += ( object sender, Database.Record selectedChild ) =>
                {
                    Database.Record assignedChild = (Database.Record)Activator.CreateInstance( typeof( TAssignType ), new object[] { (TOrignalType)selectedChild } );

                    item.Data.AddChild( ref assignedChild );
                };

                items.Add( childRecord );
            }

            _picker.Items = items;

            SetDialogLocation( _picker );
            _picker.Show();
        }

        #endregion Private Methods

        #region Event Handlers

        private async void CreateNewAssignedUser_Click( object sender, RoutedEventArgs e )
        {
            await _users.FetchOnceSafe();

            ShowPicker<Database.User, Database.AssignedUser>( _users );
        }

        private void Tree_SelectedItemChanged( object sender, RoutedPropertyChangedEventArgs<object> e )
        {
            if ( e.OldValue != null && e.OldValue.GetType().IsAssignableFrom( typeof( Tree.Item ) ) )
            {
                Tree.Item item = (Tree.Item)e.OldValue;

                RecordDetailView recordDetailView;
                if ( _recordViewControls.TryGetValue( item.Data.GetType(), out recordDetailView ) )
                {
                    recordDetailView.Visibility = Visibility.Hidden;
                }
            }

            if ( e.NewValue != null && e.NewValue.GetType().IsAssignableFrom( typeof( Tree.Item ) ) )
            {
                Tree.Item item = (Tree.Item)e.NewValue;

                RecordDetailView recordDetailView;
                if ( _recordViewControls.TryGetValue( item.Data.GetType(), out recordDetailView ) )
                {
                    Database.AssignedUser assignedUser = item.Data as Database.AssignedUser;

                    if ( assignedUser != null )
                    {
                        Database.Record potential = assignedUser.FindRecord( typeof( Database.User ), assignedUser.UserId );

                        recordDetailView.DataContext = potential ?? item.Data;
                    }
                    else
                    {
                        recordDetailView.DataContext = item.Data;
                    }

                    recordDetailView.Visibility = Visibility.Visible;
                }
            }
        }

        private void CreateNewItem_Click( object sender, RoutedEventArgs e )
        {
            var selectedItem = _tree.SelectedItem;
            if ( selectedItem.GetType() == typeof( Tree.Item ) )
            {
                Tree.Item item = (Tree.Item)selectedItem;
                item.Data.AddNewChild();
            }
        }

        private async void _import_Click( object sender, RoutedEventArgs e )
        {
            ActiveDirectory.Import dialog = new ActiveDirectory.Import() { Owner = Window.GetWindow( this ) };
            await dialog.ShowAsync();

            //             bool reload = await RedMessageBox.ShowAsync( GetWindow( this ), RedDialogType.YesNo, "Would you like to reload the user administration dialog with any newly imported users?\nYou will lose any changes you have made", "Reload contents", RedMessageBox.Mode.Info );
            // 
            //             if( reload )
            //             {
            //                 //_root.Children.Clear();
            //                 await _users.Fetch()
            //             }
        }

        private async void Ok_Executed( object sender, ExecutedRoutedEventArgs e )
        {
            _okEnabled = false;

            foreach ( Tree.Item item in _root.Items )
            {
                await item.Data.Commit( CommitComplete );
            }
        }

        private void Ok_CanExecute( object sender, CanExecuteRoutedEventArgs e )
        {
            e.CanExecute = _okEnabled;
            e.Handled = true;
        }

        private void Cancel_Executed( object sender, ExecutedRoutedEventArgs e )
        {
            Close();
        }

        private void CommitComplete( DatabaseHelper.Result result )
        {
            if ( result == DatabaseHelper.Result.Success )
            {
                Ok?.Invoke();

                Close();
            }
            else if( result == DatabaseHelper.Result.Sql )
            {
                RedMessageBox.ShowAsync( GetWindow( this ), RedDialogType.Ok, "Cannot submit invalid data from the user admin dialog.\nPlease fix it and try again", mode: RedMessageBox.Mode.Warning );
            }
            else if( result == DatabaseHelper.Result.Connection )
            {
                RedMessageBox.ShowAsync( GetWindow( this ), RedDialogType.Ok, "There was a problem connecting to the database, please wait a moment before trying again", mode: RedMessageBox.Mode.Warning );
            }

            _okEnabled = true;
        }

        private void ItemSelected( object sender, SelectionChangedEventArgs e )
        {
            DataGrid datagrid = sender as DataGrid;

            if ( datagrid != null && datagrid.SelectedItem != null )
            {
                _tree.SelectedItem.IsExpanded = true;
            }
        }

        private void _filter_TextChanged( object sender, TextChangedEventArgs e )
        {
            _root.RefreshFilter();
        }

        private bool Filter( object obj )
        {
            DataItem item = (DataItem)obj;

            return item.Title.ToLower().Contains( _filter.Text.ToLower() );
        }

        #endregion Event Handlers

        #region IEvents

        public bool Propagated { get; set; }
        public event Dialog.InterfaceClosed Ok;

        #endregion IEvents
    }
}
